package _9_博客园Redis

import (
	"fmt"
	"github.com/go-redis/redis"
)

/*如果你希望key/value的值也能作为hash结构进行操作，可以选择redis hash类型。
使用场景举例： 如果我们希望缓存一条用户信息(包括用户id、用户名、email字段)，希望能够做到局部读写用户信息（例如：读写用户名），
也能够读取整条用户信息，那么hash类型就支持这些操作。

redis hash操作主要有2-3个元素组成：
	key - redis key 唯一标识
	field - hash数据的字段名
	value - 值，有些操作不需要值
go redis hash数据常用函数：
	HSet - 根据key和field字段设置，field字段的值
	HGet - 根据key和field字段，查询field字段的值
	HGetAll - 根据key查询所有字段和值
	HIncrBy - 根据key和field字段，累加数值。
	Hincrbyfloat - 命令用于为哈希表中的字段值加上指定浮点数增量值
	HKeys - 根据key返回所有字段名
	HLen - 根据key，查询hash的字段数量
	HMGet - 根据key和多个字段名，批量查询多个hash字段值
	HMSet - 根据key和多个字段名和字段值，批量设置hash字段值
	HSetNX - 如果field字段不存在，则设置hash字段值
	HDel - 根据key和字段名，删除hash字段，支持批量删除hash字段
	HExists - 检测hash字段名是否存在。
	Hvals - 命令返回哈希表所有的值
	HSCAN 命令用于迭代哈希表中的键值对
		cursor - 游标。
		pattern - 匹配的模式。
		count - 指定从数据集里返回多少元素，默认值为 10
		HSCAN key 0 match "value"

提示：不管我们选择redis什么类型的数据，操作的时候都必须要有一个唯一的Key, 用来唯一标识一个数据。*/

func main() {
	//(0)初始化一个新的redis client
	client := redis.NewClient(&redis.Options{
		Addr:     "localhost:6379", // redis地址
		Password: "",               // redis没密码，没有设置，则留空
		DB:       0,                // 使用默认数据库
	})

	//(1)HSet根据key和field字段设置，field字段的值
	// user_1 是hash key，username 是字段名, tizi365是字段值
	err := client.HSet("user_1", "username", "tizi365").Err()
	if err != nil {
		panic(err)
	}

	//(2)HGet根据key和field字段，查询field字段的值
	// user_1 是hash key，username是字段名
	username, err := client.HGet("user_1", "username").Result()
	if err != nil {
		panic(err)
	}
	fmt.Println(username)

	//(3)HGetAll根据key查询所有字段和值
	// 一次性返回key=user_1的所有hash字段和值
	data, err := client.HGetAll("user_1").Result()
	if err != nil {
		panic(err)
	}
	// data是一个map类型，这里使用使用循环迭代输出
	for field, val := range data {
		fmt.Println(field, val)
	}

	//(4)HIncrBy根据key和field字段，累加字段的数值
	// 累加count字段的值，一次性累加2， user_1为hash key
	count, err := client.HIncrBy("user_1", "count", 2).Result()
	if err != nil {
		panic(err)
	}
	fmt.Println(count)

	//(5)HKeys根据key返回所有字段名
	// keys是一个string数组
	keys, err := client.HKeys("user_1").Result()
	if err != nil {
		panic(err)
	}
	fmt.Println(keys)

	//(6)HLen根据key，查询hash的字段数量
	size, err := client.HLen("key").Result()
	if err != nil {
		panic(err)
	}

	fmt.Println(size)

	//(7)HMGet根据key和多个字段名，批量查询多个hash字段值
	// HMGet支持多个field字段名，意思是一次返回多个字段值
	vals, err := client.HMGet("key", "field1", "field2").Result()
	if err != nil {
		panic(err)
	}
	// vals是一个数组
	fmt.Println(vals)

	//(8)HMSet根据key和多个字段名和字段值，批量设置hash字段值
	// 初始化hash数据的多个字段值
	datal := make(map[string]interface{})
	datal["id"] = 1
	datal["username"] = "tizi"

	// 一次性保存多个hash字段值
	errl := client.HMSet("key", datal).Err()
	if errl != nil {
		panic(errl)
	}

	//(9)HSetNX如果field字段不存在，则设置hash字段值
	erri := client.HSetNX("key", "id", 100).Err()
	if erri != nil {
		panic(erri)
	}

	//(10)HDel根据key和字段名，删除hash字段，支持批量删除hash字段
	// 删除一个字段id
	client.HDel("key", "id")

	// 删除多个字段
	client.HDel("key", "id", "username")

	//11.HExists检测hash字段名是否存在。
	// 检测id字段是否存在
	errj := client.HExists("key", "id").Err()
	if errj != nil {
		panic(errj)
	}
}
